﻿using System;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.Security;
using Fujitsu.Vetuma.Toolkit;
using System.Collections.ObjectModel;
using VetumaForSP2010.Resources;
using VetumaForSP2010.Configuration;
using System.Web;
using Microsoft.SharePoint.Utilities;
using System.Diagnostics;

namespace VetumaForSP2010.Layouts.VetumaForSharePoint
{
    public partial class VetumaPasswordRecovery : LayoutsPageBase
    {
        protected EncodedLiteral EncodedLiteralHeaderTitle;
        protected EncodedLiteral EncodedLiteralTitle;

        protected HtmlTableRow TableRowRecovery;

        protected Label LabelUserNameRecovery;

        protected HtmlTable TableChangePassword;

        protected HtmlTableRow TableRowOldPassword;

        protected TextBox TextBoxOldPassword;
        protected TextBox TextBoxPassword;
        protected TextBox TextBoxPasswordRetype;

        protected RequiredFieldValidator RequiredFieldValidatorOldPwd;
        protected RequiredFieldValidator RequiredFieldValidatorPwd;
        protected RequiredFieldValidator RequiredFieldValidatorPwdRetype;
        protected CompareValidator CompareValidatorPwd;

        protected Button ButtonChangePassword;

        protected Label lblInfo;

        // Allow anonymous access to this page
        protected override bool AllowAnonymousAccess
        {
            get
            {
                return true;
            }
        }

        // No need to require default layouts rights because of anonymous access
        protected override bool RequireDefaultLayoutsRights
        {
            get
            {
                return false;
            }
        }

        // No rights required to access this page
        protected override SPBasePermissions RightsRequired
        {
            get
            {
                return SPBasePermissions.EmptyMask;
            }
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            try
            {
                if (!Page.IsPostBack)
                {
                    checkRequest();
                }
            }
            catch (Exception ex)
            {
                lblInfo.Text = SPUtility.GetLocalizedString("$Resources:Error", VetumaRegister.resourcesFileName, SPContext.Current.Web.Language);
                DataAccess.logError(ex, EventLogEntryType.Error);
                TableChangePassword.Visible = false;
            }
        }

        protected void ButtonChangePassword_Click(object sender, EventArgs e)
        {
            try
            {
                if (Page.IsValid)
                {
                    if (ViewState["UserName"] != null)
                    {
                        string userName = ViewState["UserName"].ToString();
                        bool passwordChanged = changeUserPassword(userName);
                        if (passwordChanged)
                        {
                            TableChangePassword.Visible = false;
                            // Password changed successfully.
                            lblInfo.Text = SPUtility.GetLocalizedString("$Resources:PasswordChanged", VetumaRegister.resourcesFileName, SPContext.Current.Web.Language);
                        }
                        else
                        {
                            // Password change failed.
                            lblInfo.Text = SPUtility.GetLocalizedString("$Resources:PasswordChangeFailed", VetumaRegister.resourcesFileName, SPContext.Current.Web.Language);
                        }
                    }
                    else
                    {
                        throw new ApplicationException("User name missing from view state.");
                    }
                }
            }
            catch (Exception ex)
            {
                lblInfo.Text = SPUtility.GetLocalizedString("$Resources:Error", VetumaRegister.resourcesFileName, SPContext.Current.Web.Language);
                DataAccess.logError(ex, EventLogEntryType.Error);
            }
        }

        /// <summary>
        /// Changes password for the user.
        /// </summary>
        /// <param name="userName">The user name of the user whose password need to be changed.</param>
        /// <returns>Boolean value indicating whether user's password was changed.</returns>
        private bool changeUserPassword(string userName)
        {
            VetumaForSharePointConfig config = VetumaForSharePointConfig.getConfig();
            MembershipProvider currentProvider = Membership.Providers[config.RegistrationConfig.Provider];
            MembershipUser user = Membership.Providers[config.RegistrationConfig.Provider].GetUser(userName, false);
            if (user != null)
            {
                if (Request["recoveryCase"] != null)
                {
                    int recoveryCase = int.Parse(Request["recoveryCase"]);

                    bool passwordChanged = false;

                    switch (recoveryCase)
                    {
                        case 1:
                            // User wants to change password.
                            passwordChanged = user.ChangePassword(TextBoxOldPassword.Text, TextBoxPassword.Text);
                            break;
                        case 2:
                            // User has forgotten user name or password.
                            string tempPassword = user.ResetPassword("Yes");

                            passwordChanged = user.ChangePassword(tempPassword, TextBoxPassword.Text);
                            break;
                        default:
                            // Invalid request
                            throw new InvalidOperationException("Parameter recoveryCase is invalid.");
                    }

                    if (passwordChanged && user.IsLockedOut)
                    {
                        // If user is locked out, unlock user.
                        user.UnlockUser();
                    }

                    if (passwordChanged && config.RegistrationConfig.UserStore.ToLower() == "ad")
                    {
                        // Update new password to VfspList
                        DataAccess.saveVetumaUserData(user.UserName, "", VFSHasher.Encrypt(TextBoxPassword.Text, config.RegistrationConfig.VFSKey));
                    }

                    return passwordChanged;
                }
                else
                {
                    // Parameter missing
                    throw new InvalidOperationException("Parameter recoveryCase is missing.");
                }
            }
            else
            {
                throw new NullReferenceException("User cannot be found: " + userName);
            }
        }

        /// <summary>
        /// Checks the request.
        /// </summary>
        private void checkRequest()
        {
            // Request comes from hyperlink.
            if (Request["auth"] != null && Request["recoveryCase"] != null)
            {
                int auth = 0;
                int.TryParse(Request["auth"].ToString(), out auth);

                // Request comes from login page or somewhere else where is link to password recovery page.
                if (auth == 1)
                {
                    // Redirect user to Vetuma.
                    authenticateUser();
                }
                else
                {
                    throw new InvalidOperationException("Parameter auth is invalid.");
                }
            }
            // Request comes from VETUMA
            else if (Request["vetumaStatus"] != null && Request["VetumaAction"] != null)
            {
                int vetumaStatus = 0;
                int.TryParse(Request["vetumaStatus"].ToString(), out vetumaStatus);

                if (vetumaStatus > 0)
                {
                    // Handle Vetuma response.
                    handleVetumaResponse(vetumaStatus);
                }
                else
                {
                    throw new InvalidOperationException("Parameter vetumaStatus is invalid.");
                }
            }
            else
            {
                throw new InvalidOperationException("Invalid request, parameters missing: " + Request.Url.ToString());
            }

        }

        /// <summary>
        /// Handle vetuma response
        /// </summary>
        /// <param name="vetumaStatus">Parameter from request query string.</param>
        private void handleVetumaResponse(int vetumaStatus)
        {
            VetumaAuthenticationResponse response =
                new VetumaAuthenticationResponse(VetumaForSharePointConfig.getConfig().VetumaConfig.SharedSecretId,
                                                 VetumaForSharePointConfig.getConfig().VetumaConfig.SharedSecret);

            bool validate = response.Validate();

            if (validate)
            {
                switch (vetumaStatus)
                {
                    case 1:
                        // Authentication succeeded
                        // Check that user exists.
                        MembershipUser user = DataAccess.findUser(response.PersonId);
                        if (user != null)
                        {
                            checkRecoveryType(user.UserName);
                        }
                        else
                        {
                            // No user account found
                            lblInfo.Text = SPUtility.GetLocalizedString("$Resources:NoUserAccountFound", VetumaRegister.resourcesFileName, SPContext.Current.Web.Language);
                            TableChangePassword.Visible = false;
                            TableRowRecovery.Visible = false;
                        }
                        break;
                    case 2:
                        // Authentication cancelled by user
                        TableChangePassword.Visible = false;
                        TableRowRecovery.Visible = false;
                        lblInfo.Text = SPUtility.GetLocalizedString("$Resources:AuthenticationCancelled", VetumaRegister.resourcesFileName, SPContext.Current.Web.Language);
                        break;
                    case 3:
                        // Authentication error
                        TableChangePassword.Visible = false;
                        TableRowRecovery.Visible = false;
                        lblInfo.Text = SPUtility.GetLocalizedString("$Resources:AuthenticationError", VetumaRegister.resourcesFileName, SPContext.Current.Web.Language);
                        break;
                    default:
                        break;
                }

            }
            else
            {
                throw new ApplicationException("Vetuma response is invalid.");
            }
        }

        /// <summary>
        /// Checks which operation user has requested.
        /// </summary>
        /// <param name="userName"></param>
        private void checkRecoveryType(string userName)
        {
            // Check that parameter recoveryCase exists on request query string.
            if (Request["recoveryCase"] != null)
            {
                int recoveryCase = int.Parse(Request["recoveryCase"]);

                switch (recoveryCase)
                {
                    case 1:
                        string passwordChange = SPUtility.GetLocalizedString("$Resources:PasswordChange", VetumaRegister.resourcesFileName, SPContext.Current.Web.Language);
                        EncodedLiteralHeaderTitle.Text = passwordChange;
                        EncodedLiteralTitle.Text = passwordChange;
                        // User wants to change password.
                        TableRowRecovery.Visible = false;
                        break;
                    case 2:
                        string passwordRecovery = SPUtility.GetLocalizedString("$Resources:PasswordRecovery", VetumaRegister.resourcesFileName, SPContext.Current.Web.Language);;
                        EncodedLiteralHeaderTitle.Text = passwordRecovery;
                        EncodedLiteralTitle.Text = passwordRecovery;
                        // User has forgotten user name or password.
                        // Hide old password controls.
                        LabelUserNameRecovery.Text = userName;
                        TableRowOldPassword.Visible = false;
                        break;
                    default:
                        // Invalid request
                        throw new InvalidOperationException("Parameter recoveryCase is invalid.");
                }
                ViewState["UserName"] = userName;
            }
            else
            {
                // Parameter missing
                throw new InvalidOperationException("Parameter recoveryCase is missing.");
            }
        }

        /// <summary>
        /// Redirects user to Vetuma
        /// </summary>
        private void authenticateUser()
        {
            // Authentication in Vetuma can be successfull, it can be cancelled by user or error can occur.
            // Define urls for these different scenarios.
            string url = "https://" + Request.Url.Host;

            if (Request.Url.Port != 80)
            {
                url += ":" + Request.Url.Port.ToString();
            }
            url += Request.Url.LocalPath;

            string recoveryCase = "recoveryCase=" + Request["recoveryCase"].ToString();

            string successUrl = url + "?vetumaStatus=1&VetumaAction=1&" + recoveryCase;

            // No need to add recovery case on these urls because in these cases user is not authentication by Vetuma.
            string cancelUrl = url + "?vetumaStatus=2&VetumaAction=1";
            string errorUrl = url + "?vetumaStatus=3&VetumaAction=1";

            Collection<VetumaLoginMethod> methods = VetumaRegister.getMethods();

            VetumaAuthenticationRequest request = new VetumaAuthenticationRequest(
                    SPUtility.GetLocalizedString("$Resources:Next", VetumaRegister.resourcesFileName, SPContext.Current.Web.Language),
                    SPUtility.GetLocalizedString("$Resources:NoJavascript", VetumaRegister.resourcesFileName, SPContext.Current.Web.Language),
                    "fi",
                    methods,
                    new Uri(successUrl), // Success
                    new Uri(cancelUrl), // Cancel
                    new Uri(errorUrl), // Error
                    new Uri(VetumaForSharePointConfig.getConfig().VetumaConfig.PostUrl),
                    VetumaForSharePointConfig.getConfig().VetumaConfig.SharedSecretId,
                    VetumaForSharePointConfig.getConfig().VetumaConfig.SharedSecret,
                    VetumaForSharePointConfig.getConfig().VetumaConfig.ApplicationId,
                    VetumaForSharePointConfig.getConfig().VetumaConfig.ConfigurationId);

            //request.ExtraData = "VTJ1";
            //request.ExtraData = "VTJTT=VTJ-VETUMA-Perus";

            // Submit the authentication request
            try
            {
                request.Submit();
            }
            catch (System.Threading.ThreadAbortException)
            {
                // This error is caused by redirection in sharepoint. No need to handle.
                // Must do something else upper catch is catching this.
                url = "";
            }
        }
    }
}
